#!/usr/bin/perl
# replicate-file-once.pl
# Copyright (C) 2006, 2007  Stephane Alnet
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 


# Usage: local-replicate-file-once.pl <file> <ssh-login>
use strict;
use warnings;
use lib '/home/manager/lib';
use CCNCore::IPC::Spool;

our $file   = shift;
our $remote = shift;

sub _debug($) { print STDERR "$_[0]\n"; }

die "INTERNAL ERROR: Must provide file and remote server information."
    unless defined $file and defined $remote;

my $timer = 20;
sub catch_alarm {
    # Respool the request (remote server may be down or busy)
    my $spool = new CCNCore::IPC::Spool;
    $spool->spool_request("replicate-file-once $file $remote");
    exit 0;
}
$SIG{'ALRM'} = \&catch_alarm;
alarm($timer);

sub get_remote_info()
{
    open my $ssh, '-|', '/usr/bin/ssh', '-nT', $remote, '/home/manager/bin/local-file-info.pl', $file
        or die "ERROR: $remote local-file-info failed: $!";
    local $/;
    my $content = <$ssh>;
    close $ssh;
    
    # SSH failed
    die "ERROR: $remote failed ($! $?)"
        if not defined $content;
    # remote script failed
    die "ERROR: $remote empty"
        if $content eq '';
    
    chomp $content;

    my ($remote_size,$remote_mtime) = split(/ /,$content);
    $remote_size  ||= 0;
    $remote_mtime ||= 0;
    return ($remote_size,$remote_mtime);
}

sub get_local_info()
{
    my @stat = stat $file;
    if( $#stat >= 0 )
    {
        my $local_size  = $stat[7];
        my $local_mtime = $stat[9];
        return ($local_size, $local_mtime);
    }
    else
    {
        return (0,0);
    }    
}

my @remote_info = get_remote_info();
my @local_info  = get_local_info();

# Weird, the file doesn't exist locally or remotely.
if( $remote_info[1] == 0 && $local_info[1] == 0 )
{
    exit 0;
}

# TBD Use -o BindAddress

# The file exists remotely but not locally (weird we got asked to transfer it the other way around).
if( $remote_info[1] != 0 && $local_info[1] == 0 )
{
    _debug "/usr/bin/scp -p $remote:$file $file";
    exec "/usr/bin/scp", '-p', "$remote:$file", $file;
    exit 0;
}

# The file exists locally but not remotely.
if( $remote_info[1] != 0 && $local_info[1] == 0 )
{
    _debug "/usr/bin/scp -p $file $remote:$file";
    exec "/usr/bin/scp", '-p', $file, "$remote:$file";
    exit 0;
}

# The file exists on both sides. Check whether they are identical.
# Identical means: sizes are identical, and mtime is within 2 seconds
# (which should be the case since we do "scp -p").
if(  $remote_info[0] == $local_info[0] 
 and abs($remote_info[1] - $local_info[1]) <= 2 )
{
    exit 0;
}

# OK, the files exist on both sides and are different.
# Find the most recent one and copy in that direction.
if( $remote_info[1] < $local_info[1] )
{
    _debug "Remote is older, copy $file from local.";
    exec "/usr/bin/scp", '-B', '-q', '-p', $file, "$remote:$file";
    exit 0;
}
else
{
    _debug "Remote is newer, copy $file from remote.";
    exec "/usr/bin/scp", '-B', '-q', '-p', "$remote:$file", $file;
    exit 0;
}
# The end.
